package com.akaovi.chatroom.process;

import com.akaovi.chatroom.domain.User;
import com.akaovi.chatroom.domain.vo.OnlineRl;
import com.akaovi.chatroom.mess.*;
import com.akaovi.chatroom.utils.CommonUtils;
import com.akaovi.chatroom.utils.DBUtils;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;

/**
 * @author akaovi
 * @version 1.0
 * @description
 * @date 2022/12/7 16:37
 * @since 2022/12/7 16:37
 */
public class UserThread implements Runnable {

    public Socket socket = null;
    public ObjectInputStream ois = null;
    public ObjectOutputStream oos = null;
    public boolean isOnline = true;

    public UserThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            ois = new ObjectInputStream(socket.getInputStream());
            // 监听用户的请求
            while (isOnline) {
                Message mess = (Message) ois.readObject();
                // 接到请求，分发任务
                dispatcher(mess);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CommonUtils.closeResource(socket, oos, ois);
        }
    }

    /**
     * 请求分发器
     *
     * @param mess 待处理的基本消息体
     */
    public void dispatcher(Message mess) {
        if (mess.type == MessType.Login) {
            login((Login) mess);
        } else if (mess.type == MessType.SendMess) {
            sendMess((SendMess) mess);
        } else if (mess.type == MessType.Logout) {
            logout((Logout) mess);
        } else if (mess.type == MessType.Register) {
            handleRegister((Register) mess);
        } else if (mess.type == MessType.AddFriend) {
            handleAddFriend((AddOrDeleteFriend) mess);
        } else if (mess.type == MessType.DeleteFriend) {
            handleDeleteFriend((AddOrDeleteFriend) mess);
        } else if (mess.type == MessType.AgreeAddFriend) {
            handleAgreeAddFriend((AddOrDeleteFriend) mess);
        } else {
            System.out.println("识别不了");
        }
    }

    /**
     * 处理同意添加好友消息
     * @param mess
     */
    private void handleAgreeAddFriend(AddOrDeleteFriend mess) {
        try {
            String sql = "INSERT INTO user_relationship (user_id, friend_id, v_msg) VALUES (?, ?, ?);";
            boolean update = DBUtils.update(sql, mess.from, mess.account, mess.detail);
            if (update) {
                DBUtils.update(sql, mess.account, mess.from, mess.detail);
                // 找到原始发送的人
                UserThread to = UserManage.getUserByAccount(Integer.parseInt(mess.from));
                to.oos.writeObject(mess);
                to.oos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理删除好友消息
     * @param mess
     */
    private void handleDeleteFriend(AddOrDeleteFriend mess) {
        String sql = "UPDATE user_relationship SET is_deleted = 1 WHERE user_id = ? and friend_id = ?;";
        boolean update = DBUtils.update(sql, mess.from, mess.account);
        if (update) {
            DBUtils.update(sql, mess.account, mess.from);
        }
    }

    /**
     * 添加好友
     *
     * @param mess
     */
    private void handleAddFriend(AddOrDeleteFriend mess) {
        // 是否在线
        UserThread to = UserManage.getUserByAccount(Integer.parseInt(mess.account));
        try {
            if (to == null) {
                oos.writeObject(new ResponseStatus(MessType.AgreeAddFriend, 300, "用户不在线"));
                oos.flush();
            } else {
                to.oos.writeObject(mess);
                to.oos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 注册
     *
     * @param mess
     */
    private void handleRegister(Register mess) {
        String account = null;
        try {
            oos = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 8; i++) {
            account = CommonUtils.generateAccount();
            String pre_sql = "select id from user where account = ?";
            User user = DBUtils.selectOne(User.class, pre_sql, account);
            if (user == null || user.getId() == null) {
                if (i == 7) {
                    try {
                        oos.writeObject(new ResponseStatus(MessType.ReRegister, 400, "注册失败"));
                        oos.flush();
                        isOnline = false;
                        return;
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        CommonUtils.closeResource(socket, oos, ois);
                    }
                }
                break;
            }
        }
        String sql = "INSERT INTO user (account, password, username) VALUES (?, ?, ?);";
        DBUtils.update(sql, account, mess.pwd, mess.username);
        try {
            oos.writeObject(new ResponseStatus(MessType.ReRegister, 200, account));
            oos.flush();
            isOnline = false;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CommonUtils.closeResource(socket, oos, ois);
        }
    }

    /**
     * 用户登录
     *
     * @param mess 登录消息体
     */
    public void login(Login mess) {
        try {
            // 走数据库
            // 登录一定是第一次创建
            if (oos == null) {
                oos = new ObjectOutputStream(socket.getOutputStream());
            }
            String sql = "select username from user where is_deleted = 0 and account = ? and password = ?";
            User user = DBUtils.selectOne(User.class, sql, mess.account, mess.pwd);
            if (user != null && user.getUsername() != null) {
                oos.writeObject(ResponseStatus.ok(MessType.ReLogin));
                oos.flush();
                // 管理在线用户
                UserManage.add(mess.account, this);
                // todo
                System.out.println(mess.account + "登录");
                // 登录后获取全部好友信息
                String sql2 = "select friend_id friendId, username from user_relationship ur " +
                        "left join user u on u.account = ur.friend_id " +
                        "where u.is_deleted = 0 and ur.is_deleted = 0 and user_id = ?";
                List<OnlineRl> ls = DBUtils.selectAll(OnlineRl.class, sql2, mess.account);
                int[] accounts = ls.stream().mapToInt(OnlineRl::getFriendId).toArray();
                String[] usernames = ls.stream().map(OnlineRl::getUsername).toList().toArray(new String[0]);
                Boolean[] status = ls.stream().map(value -> UserManage.getUserByAccount(value.getFriendId()) != null).toList().toArray(new Boolean[0]);
                oos.writeObject(new FriendsMess(MessType.FriendsMess, accounts, usernames, status));
                oos.flush();
                // 通知上线
                UserManage.broadcast(new OnOrOffLineMess(MessType.OnlineMess, mess.account));
            } else {
                // 用户名或密码错误 / 禁止登陆
                oos.writeObject(ResponseStatus.fail(MessType.ReLogin, Constant.USER_ERROR));
                oos.flush();
                isOnline = false;
                System.out.println(mess.account + "登陆失败");
                CommonUtils.closeResource(socket, oos, ois);
            }
        } catch (Exception e) {
            e.printStackTrace();
            isOnline = false;
            CommonUtils.closeResource(socket, oos, ois);
        }
    }

    /**
     * 用户登出
     *
     * @param mess 登出消息体
     */
    public void logout(Logout mess) {
        UserThread user = UserManage.getUserByAccount(mess.account);
        UserManage.remove(mess.account);
        user.isOnline = false;
        UserManage.broadcast(new OnOrOffLineMess(MessType.OfflineMess, mess.account));  // 告知其他人我下线
    }

    /**
     * 转发消息
     *
     * @param mess 用户传来待发送的消息体
     */
    public void sendMess(SendMess mess) {
        try {
            // 获取对方(在线 or 不在线)
            UserThread toUser = UserManage.getUserByAccount(mess.to);
            if (toUser == null) {
                System.out.println("用户不在线");
                // 用户自己存储待发送的离线信息
            } else {
                // 转发信息
                toUser.oos.writeObject(new AcceptMess(MessType.AcceptMess, mess.from, mess.data));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
